Skip to main content

Axir ERC20Paymaster

The ERC20Paymaster is an ERC-4337 compliant Paymaster contract that allows sponsoring gas fees in exchange for ERC-20 tokens. It supports various payment modes, including user-paid transactions with or without limits, and transactions with guarantors.

Overview

The ERC20Paymaster contract enables users to pay for transaction fees using ERC-20 tokens instead of the native cryptocurrency (e.g., ETH). It uses oracles to fetch the latest token prices and supports standard and up-rebasing ERC-20 tokens.

Key features:

  • Support for multiple payment modes
  • Dynamic pricing based on oracle data
  • Refund of excess tokens
  • Configurable price markup

Constructor

constructor(
IERC20Metadata _token,
IEntryPoint _entryPoint,
IOracle _tokenOracle,
IOracle _nativeAssetOracle,
uint32 _stalenessThreshold,
address _owner,
uint32 _priceMarkupLimit,
uint32 _priceMarkup,
uint256 _refundPostOpCost,
uint256 _refundPostOpCostWithGuarantor
)

Initializes the ERC20Paymaster contract with the following parameters:

  • _token: The ERC20 token used for transaction fee payments
  • _entryPoint: The ERC-4337 EntryPoint contract
  • _tokenOracle: Oracle contract for token to USD prices
  • _nativeAssetOracle: Oracle contract for native asset (ETH, Matic, etc.) to USD prices
  • _stalenessThreshold: Time in seconds after which an oracle result is considered stale
  • _owner: Address to be set as the contract owner
  • _priceMarkupLimit: Maximum allowed price markup percentage (1e6 = 100%)
  • _priceMarkup: Initial price markup percentage (1e6 = 100%)
  • _refundPostOpCost: Estimated gas cost for token refunds
  • _refundPostOpCostWithGuarantor: Estimated gas cost for token refunds with a guarantor

Payment Modes

The paymaster supports four modes:

  1. User pays, no limit
  2. User pays, with a limit
  3. User pays with a guarantor, no limit
  4. User pays with a guarantor, with a limit
note

Modes 2 and 3 are not compatible with the default storage access rules of ERC-4337 and require a whitelist for the guarantors.

Key Functions

validatePaymasterUserOp

function _validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal override returns (bytes memory context, uint256 validationResult)

Validates the paymaster data, calculates the required token amount, and transfers the tokens.

postOp

function _postOp(
PostOpMode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) internal override

Performs post-operation tasks, such as refunding excess tokens and attempting to pay back the guarantor if there is one.

updateMarkup

function updateMarkup(uint32 _priceMarkup) external onlyOwner

Allows the contract owner to update the price markup percentage.

withdrawToken

function withdrawToken(address to, uint256 amount) external onlyOwner

Allows the contract owner to withdraw a specified amount of tokens from the contract.

getPrice

function getPrice() public view returns (uint192)

Fetches the latest token price using the configured oracles.

getHash

function getHash(
PackedUserOperation calldata userOp,
uint48 validUntil,
uint48 validAfter,
uint256 tokenLimit
) public view returns (bytes32)

Hashes the user operation data for signature verification.

Events

MarkupUpdated

event MarkupUpdated(uint32 priceMarkup)

Emitted when the price markup is updated.

UserOperationSponsored

event UserOperationSponsored(
bytes32 indexed userOpHash,
address indexed user,
address indexed guarantor,
uint256 tokenAmountPaid,
uint256 tokenPrice,
bool paidByGuarantor
)

Emitted when a user operation is sponsored by the paymaster.

Custom Errors

The contract defines several custom errors for various failure conditions:

  • PaymasterDataModeInvalid()
  • PaymasterDataLengthInvalid()
  • TokenAmountTooHigh()
  • TokenLimitZero()
  • PriceMarkupTooHigh()
  • PriceMarkupTooLow()
  • OraclePriceStale()
  • OraclePriceNotPositive()
  • OracleDecimalsInvalid()